package com.lcj.OwnerMyBatis.sqlSession;

import com.lcj.OwnerMyBatis.pojo.Configuration;
import com.lcj.OwnerMyBatis.pojo.MappedStatement;
import com.mysql.cj.util.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.List;

/**
 * @Author：liuchangjun
 * @Date：2021/10/27
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DefaultSqlSession implements SqlSession {


    private Configuration configuration;

    @Override
    public <E> List<E> selectList(String statementId, Object... params) throws Exception {
        //将要去Executor里的query方法
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        List<Object> list = simpleExecutor.query(configuration,mappedStatement,params);
        return (List<E>) list;
    }

    @Override
    public <T> T selectOne(String statementId, Object... params) throws Exception {
        if(StringUtils.isNullOrEmpty(statementId)){
            return null;
        }
        List<Object> objects = selectList(statementId,params);
        if(objects!= null){
            return (T) objects.get(0);
        }
        return null;
    }

    /**
     * 使用JDK动态代理，生成动态代理对象
     * @param clazz
     * @param <T>
     * @return
     */
    @Override
    public <T> T getMapper(Class<?> clazz) {
       Object proxyObject = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //根据不同情况，掉用不同方法
                /**
                 *  准备参数：
                 *    1：statementId--namespace.id---接口权限定名.方法名
                 *
                 */
               String methodName = method.getName();
               String className = method.getDeclaringClass().getName();
               String statementId = className+"."+methodName;
                /**
                 * 获取被调用方法，返回值类型
                 */
                Type type = method.getGenericReturnType();
                /**
                 * 是否有泛型类型参数话，有就是集合              */
                if(type instanceof ParameterizedType){
                    List<Object> objects = selectList(statementId,args);
                    return objects;
                }
                return selectOne(statementId,args);
            }
        });
        return (T) proxyObject;
    }
}
